/**
 * 新验证插件,超好用
 * 更新:
 * 采用layer的tip提示
 * 修正不通过时候跳转到函数
 *
 */

(function ($) {

    //要验证的input的选择器
    var valid_input_types = "input[type=text],input[type=password],textarea,select";

    //第一个input元素
    var firstObj = null;

    /**
     * 显示提示小图标
     * @param $iconTip
     * @param $input
     */
    function showIcon($iconTip, $input) {
        var top = $input.offset().top;
        var left = $input.offset().left + $input.width() + 5;
        $iconTip.css({top: top + "px", left: left + "px"});
        $iconTip.show();
    }

    /**
     * 显示详细信息
     * @param $detailTip
     * @param $iconTip
     */
    function showDetailTips($detailTip, $iconTip) {
        var top = $iconTip.offset().top - 10;
        var left = $iconTip.offset().left - $detailTip.width();
        $detailTip.css({top: top + "px", left: left + "px"});
        $detailTip.slideDown(200);
    }

    /**
     * 隐藏提示
     * @param $input
     */
    function clearInputTips($input) {
        var $iconTip = $("div#validIcon" + $input.attr("id")).hide();
    }

    /**
     * 创建显示提示的元素
     */
    function createTipElement($input) {

        var $body = $('body');

        //小图标,默认是隐藏的
        var $iconTip = $("<div class='validIcon'>&nbsp;</div>").attr("id", "validIcon" + $input.attr("id")).hide().appendTo($body);

        //详细提示信息
        //错误提示
        var $detailTip = $('<div class="validator-ui validator-ui-tips validator-anim" style="z-index:19891016; position: absolute;"><div class="validator-ui-content"><span class="tip_text">提示</span> <i class="validator-ui-TipsG validator-ui-TipsL"></i></div></div>').attr("id", "vtip" + $input.attr("id")).hide().appendTo($body);

        $iconTip.hover(function () {
            //进入图标,显示提示信息
            var $span = $detailTip.find("span.tip_text").text("");

            if ($iconTip.hasClass("validIcon-error")) {
                $span.text($input.attr("errorMsg"));
                showDetailTips($detailTip, $iconTip);
            } else if ($iconTip.hasClass("validIcon-info")) {
                var msg = $input.attr("sysMsg") || $input.attr("tip");
                $span.text(msg);
                showDetailTips($detailTip, $iconTip);
            }

        }, function () {
            //离开
            $detailTip.slideUp();

        });
    }

    /**
     * 显示提示信息
     * @param $input
     */
    function ShowTips($input) {

        //对与否小图标
        var $iconTip = $("div#validIcon" + $input.attr("id")).hide();
        $input.removeClass("input_validation-failed");

        //没有提示信息就跳过
        var msg = $input.attr("sysMsg") || $input.attr("tip");
        if (msg == undefined || msg == "") return;

        $iconTip.removeClass("validIcon-success");
        $iconTip.removeClass("validIcon-error");
        $iconTip.addClass("validIcon-info");
        showIcon($iconTip, $input);

    }

    /**
     * 显示验证结果
     * @param $input
     */
    function ShowResult($input) {

        //对与否小图标
        var $iconTip = $("div#validIcon" + $input.attr("id")).hide();

        //如果input元素不可见，就不显示提示
        if ($input.is(':hidden')) {
            console.log("该表单元素不可见!!" + $input.attr("name"));
            return;
        }

        if ($input.attr("errorMsg")) {
            //错误
            $input.addClass("input_validation-failed");

            $iconTip.removeClass("validIcon-success");
            $iconTip.removeClass("validIcon-info");
            $iconTip.addClass("validIcon-error");
            showIcon($iconTip, $input);
        }
        else if ($input.val().replace(/ /gi, "") != "") {//如果input什么都没有填也不显示正确的打钩
            //正确
            $iconTip.removeClass("validIcon-error");
            $iconTip.removeClass("validIcon-info");
            $iconTip.addClass("validIcon-success");
            showIcon($iconTip, $input);
        }

    }

    /**
     * 验证一个input元素
     * @param $input
     * @returns {boolean}
     */
    function validate($input) {
        /*
         obj.attr("isWEIRemoteUrlisWEIRemoteUrlisWEIRemoteUrl", "0");
         var isWEIRemoteUrlisWEIRemoteUrlisWEIRemoteUrl = 0;//0:等待处理，1成功，2失败
         obj.attr("errMsg", "");
         $("div#vtip").remove();
         $("div#t" + obj.attr("id")).remove();
         obj.removeClass("input_validation-failed");
         */

        $input.attr("errorMsg", "");

        //对于隐藏控件、只读控件、已禁用的控件 不进行前端校验
        if ($input.css("display") == "none") return true;
        if ($input.attr("readonly") == true) return true;
        if ($input.attr("disabled") == true) return true;
        if ($input.attr("notvalid") == "true") {
            return true;
        }

        var validSettings = $input.data("validSettings");

        //没有valType 和 required 属性，不校验
        /*if (validSettings.valType == undefined
            && validSettings.required == undefined) {
            return true
        }*/
        if (validSettings.valType == undefined
            && $input.prop("required") == false) {
            return true
        }

        //input的值域
        var objval = $input.val();

        objval = $.trim(objval);//去首尾空

        if (objval == "") {
            if (validSettings.required || validSettings.required == "true") {
                $input.attr("errorMsg", "请填写该信息");
                return false;
            } else {
                return true;
            }
        }


        /*
         //允许为空，且无值则不校验
         if (objval == null || objval == undefined || objval.replace(/ /gi, "") == "") return true;
         */

        if (validSettings.valType) {
            var reg = "";
            switch (validSettings.valType.toLowerCase()) {
                case "url":
                    reg = /^(http|https|ftp):\/\/[a-zA-Z0-9\-._]+\.[a-zA-Z]{2,3}(:[a-zA-Z0-9]*)?\/?([a-zA-Z0-9\-._?,'/\\+&%$#=~])*$/;
                    if (!reg.test($input.val())) {
                        $input.attr("errorMsg", "您输入的Url格式不正确");
                        return false;
                    }
                    break;

                case "email":
                    reg = /^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/;
                    if (!reg.test($input.val())) {
                        $input.attr("errorMsg", "您输入的Email格式不正确");
                        return false;
                    }
                    break;
                case "number":
                    reg = /^(-?\d+)(\.\d+)?$/;
                    if (!reg.test($input.val())) {
                        $input.attr("errorMsg", "请输入数字");

                        return false;
                    }
                    break;
                case "telphone":
                    reg = /^\d{3}-\d{8}$|^\d{4}-\d{8}$/;
                    if (!reg.test($input.val())) {
                        $input.attr("errorMsg", "请输入正确的电话号码，例如0755-88880000");

                        return false;
                    }
                    break;
                case "mobile":
                    reg = /^(133|153|180|181|189|177|173|130|131|132|155|156|145|185|186|176|185|134|135|136|137|138|139|150|151|152|158|159|182|183|184|157|187|188|147|178|184)\d{8}$/;
                    if (!reg.test($input.val())) {
                        $input.attr("errorMsg", "请输入正确的手机号码");
                        return false;
                    }
                    break;
                case "tel_or_mobile":
                    //验证电话或者手机
                    var reg1 = /^\d{3}-\d{8}$|^\d{4}-\d{8}$/;
                    var reg2 = /^(133|153|180|181|189|177|173|130|131|132|155|156|145|185|186|176|185|134|135|136|137|138|139|150|151|152|158|159|182|183|184|157|187|188|147|178|184)\d{8}$/;
                    if (!reg1.test($input.val()) && !reg2.test($input.val())) {
                        //同时验证不成功
                        $input.attr("errorMsg", "请输入正确的电话号码，例如0755-88880000，或者正确的手机号码！");
                        return false;
                    }
                    break;
                case "ip":
                    reg = /^(([1-9]|([1-9]\d)|(1\d\d)|(2([0-4]\d|5[0-5])))\.)(([1-9]|([1-9]\d)|(1\d\d)|(2([0-4]\d|5[0-5])))\.){2}([1-9]|([1-9]\d)|(1\d\d)|(2([0-4]\d|5[0-5])))$/;
                    if (!reg.test($input.val())) {
                        $input.attr("errorMsg", "请输入正确的IP地址，例如 127.0.0.1");
                        return false;
                    }
                    break;
                case "int":
                    reg = /^\d*$/;

                    if (!reg.test($input.val())) {
                        $input.attr("errorMsg", "请输入整数");
                        return false;
                    }
                    break;
                case "date":
                    reg = /^(([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})-(((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01]))|((0[469]|11)-(0[1-9]|[12][0-9]|30))|(02-(0[1-9]|[1][0-9]|2[0-8]))))|((([0-9]{2})(0[48]|[2468][048]|[13579][26])|((0[48]|[2468][048]|[3579][26])00))-02-29)$/;
                    if (!reg.test($input.val())) {
                        $input.attr("errorMsg", "请输入格式正确的日期，例如：2010-02-28");
                        return false;
                    }
                    break;
                case "pwd":
                    reg = /^[0-9|A-Z|a-z]{6,50}$/;
                    if (!reg.test($input.val())) {
                        $input.attr("errorMsg", "请输入长度6位以上\"字母\"或\"数字\"组合密码");
                        return false;
                    }
                    break;
                case "idcard":
                    reg = /^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{4}$/;  //18位身份证号码
                    reg = /^((11|12|13|14|15|21|22|23|31|32|33|34|35|36|37|41|42|43|44|45|46|50|51|52|53|54|61|62|63|64|65)[0-9]{4})(([1|2][0-9]{3}[0|1][0-9][0-3][0-9][0-9]{3}[X0-9])|([0-9]{2}[0|1][0-9][0-3][0-9][0-9]{3}))$/;

                    if ($input.val().length == 15)   //15位身份证号码
                        reg = /^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$/;
                    if (!reg.test($input.val())) {
                        $input.attr("errorMsg", "您输入的身份证格式不正确");
                        return false;
                    }
                    break;
                case "hanzi":
                    reg = /^[\u4e00-\u9fa5],{0,}$/;
                    if (!reg.test($input.val())) {
                        $input.attr("errorMsg", "请输入汉字");
                        return false;
                    }
                    break;
                //验证有两位小数的正实数
                case "xiaoshu":
                    reg = /^[0-9]+(.[0-9]{2})?$/;
                    if (!reg.test($input.val())) {
                        $input.attr("errorMsg", "必须有两个小数位");
                        return false;
                    }
                    break;
                //验证更加广泛的小数
                case"xiaoshu2":
                    //reg = /^[0-9]+(.[0-9]*)?$/;
                    if (!$.isNumeric($input.val())) {//!reg.test(obj.val())
                        $input.attr("errorMsg", "请输入小数");
                        return false;
                    }
                    break;
                //验证密码
                case "mm":
                    reg = /^\w{5,17}$/;
                    //alert(reg.test(obj.val()));
                    if (!reg.test($input.val())) {
                        $input.attr("errorMsg", "密码不能为中文且长度在6-18位");
                        return false;
                    }
                    break;

                case "username":
                    reg = /^[0-9|A-Z|a-z|_]{6,50}$/;
                    if (!reg.test($input.val())) {
                        $input.attr("errorMsg", "请输入长度6位以上字母、数字、下划线组合的用户名");
                        return false;
                    }
                    break;
            }
        }

        /*
         if (validSettings.regExp) {
         reg = validSettings.regExp;
         if (!reg.test($input.val())) {
         if (!$input.attr("errorMsg")) {
         $input.attr("errorMsg", "格式不对，请重新录入");
         }
         ShowResult($input);
         return false;
         }
         }
         */


        var objFloat = parseFloat(objval);
        var objDate = stringToDate(objval);

        //验证小于
        if (validSettings.min) {

            $("div#vtip").remove();
            $(validSettings.min).attr("errorMsg", "");
            $(validSettings.min).removeClass("input_validation-failed");

            switch (validSettings.valType.toLowerCase()) {
                case "date":

                    var minDate = stringToDate(validSettings.min);
                    if (objDate < minDate && objDate != 0 && minDate != 0) {
                        $input.attr("errorMsg", "不能小于" + validSettings.min);
                        return false;
                    }

                    break;
                case "number":
                case "int":
                default:

                    var theMin = parseFloat(validSettings.min);
                    if (objFloat < theMin) {
                        $input.attr("errorMsg", "不能小于" + theMin);
                        return false;
                    }

                    break;
            }

        }

        //验证大于
        if (validSettings.max) {

            $("div#vtip").remove();
            $(validSettings.max).attr("errorMsg", "");
            $(validSettings.max).removeClass("input_validation-failed");


            switch (validSettings.valType.toLowerCase()) {
                case "date":

                    var maxDate = stringToDate(validSettings.max);

                    if (objDate > maxDate && objDate != 0 && maxDate != 0) {

                        $input.attr("errorMsg", "不能大于" + validSettings.max);

                        return false;
                    }
                    break;
                case "number":
                case "int":
                default:
                    var theMax = parseFloat(validSettings.max);

                    if (objFloat > theMax) {
                        $input.attr("errorMsg", "不能大于" + theMax);

                        return false;
                    }
                    break;
            }

        }

        //验证最小长度
        if (validSettings.minLength) {
            if (objval.length < validSettings.minLength) {
                $input.attr("errorMsg", "最短录入长度为" + validSettings.minLength);
                return false;
            }
        }

        //验证最大长度
        if (validSettings.maxLength) {
            if (objval.length > validSettings.maxLength) {
                $input.attr("errorMsg", "最大录入长度为" + validSettings.maxLength);
                return false;
            }
        }


        //最后进行远程验证
        if (validSettings.remoteUrl) {

            var isRemoteUrlCheck = false;//是否验证成功

            if (validSettings.remote_notValidValue && objval == validSettings.remote_notValidValue) {
                console.log("不远程验证的值:" + validSettings.remote_notValidValue);
                //这里不进行远程验证
                isRemoteUrlCheck = true;
            } else {

                //去验证
                var url = validSettings.remoteUrl;

                if (url.indexOf("?") > 0)
                    url = url + "&param=" + encodeURI(objval);//escape(obj.val());
                else
                    url = url + "?param=" + encodeURI(objval);//escape(obj.val());
                //alert(url);

                $.ajax({
                    type: "GET",
                    url: url + "&rnd=" + Math.random(),
                    dataType: "json",
                    async: false,
                    success: function (data) {
                        if (data.result != 1) {
                            //失败
                            $input.attr("errorMsg", data.msg);
                        }
                        else {
                            //成功
                            isRemoteUrlCheck = true;
                        }
                    }
                });
            }

            return isRemoteUrlCheck;
        }

        return true;
    }

    /**
     * 字符串转化为日期
     * @param v
     * @returns {number}
     */
    function stringToDate(v) {
        try {
            v = v.replace(/-/gi, "/").replace(/\./gi, "/");
            return Date.parse(v);
        }
        catch (e) {
            return 0;
        }
    }

    var methods = {
        /**
         * 初始化
         * @param settings
         * @returns {*}
         */
        init: function (settings) {
            var opts = $.extend({}, $.fn.validatorX.defaults, settings); //使用jQuery.extend 覆盖插件默认参数
            return this.each(function () {

                var self = this;//该元素本身
                var $this = $(self);//JQ对象

                $this.find(valid_input_types).each(function (index) {

                    var $myself = $(this);//代表需要验证的input元素
                    var data = {};

                    if ($myself.attr("valType"))
                        data["valType"] = $(this).attr("valType");

                    if ($myself.attr("min"))
                        data["min"] = $(this).attr("min");

                    if ($myself.attr("max"))
                        data["max"] = $(this).attr("max");

                    if (!$myself.attr("id"))
                        $myself.attr("id", "ctrl" + index);

                    if ($myself.attr("minLength"))
                        data["minLength"] = $myself.attr("minLength");

                    if ($myself.attr("maxLength"))
                        data["maxLength"] = $myself.attr("maxLength") || $myself.attr("MaxLength");

                    //是否必须
                    if ($myself.attr("required"))
                        data["required"] = $myself.attr("required");

                    //远程验证url
                    if ($myself.attr("remoteUrl"))
                        data["remoteUrl"] = $myself.attr("remoteUrl");

                    //显示提示的方向
                    if ($myself.attr("tipStyle")) {
                        data["tipStyle"] = $myself.attr("tipStyle");
                    } else {
                        data["tipStyle"] = "left";
                    }

                    //远程不验证的value
                    if ($myself.attr("remote_notValidValue")) {
                        data["remote_notValidValue"] = $(this).attr("remote_notValidValue");
                    }

                    if ($myself.attr("errorMsg")) {
                        data["errorMsg"] = $myself.attr("errorMsg");
                    }

                    $myself.data("validSettings", $.extend({}, data, eval("(" + $myself.attr("validSettings") + ")")));
                    //validSettings="{tipStyle:'bottom'}"

                    createTipElement($myself);//创建提示信息元素

                    $myself.focus(function () {
                        //获得焦点
                        ShowTips($myself);
                    }).hover(function () {
                        //hover进入

                    }, function () {
                        //hover离开
                    }).keyup(function () {
                        //按键弹起

                        var validSettings = $myself.data("validSettings");
                        if (!validSettings.maxLength && !validSettings.minLength) {
                            return;
                        }

                        //超出长度裁剪
                        if (validSettings.maxLength && $myself.val().length > validSettings.maxLength) {
                            $myself.val($myself.val().substring(0, validSettings.maxLength));
                        }

                        /*
                         if (($(this).data("validSettings").calcRemain == "true" || $(this).data("validSettings").calcRemain == true)) {
                         }
                         */

                        var msg = "已录入" + $myself.val().length + "个字符,";
                        if (validSettings.minLength) {
                            msg += "最少录入" + validSettings.minLength + "个,";
                        }
                        if (validSettings.maxLength) {
                            msg += "最多录入" + validSettings.maxLength + "个.";
                        }

                        //+ "，还可以录" + (validSettings.maxLength - $myself.val().length) + "个"

                        $myself.attr("sysMsg", msg);
                        //ShowTips($myself);


                    }).keydown(function (event) {
                        //按键按下

                        var validSettings = $myself.data("validSettings");

                        if (validSettings.valType == undefined) return;

                        //按下ctrl、shift、alt 等功能键
                        if (event.ctrlKey || event.shiftKey || event.altKey) return true;

                        //方向键 && F1..F12
                        var key = event.keyCode;
                        if (key >= 33 && key <= 47) return true;
                        if (key >= 112 && key <= 137) return true;


                        //8 = BackSpace	9 = Tab		12 = Clear	13 = Enter	16 = Shift_L	17 = Control_L	18 = Alt_L	19 = Pause		20 = Caps_Lock	27 = Escape Escape
                        var sCode = ";8;9;12;13;16;17;18;19;20;27;";
                        if (sCode.indexOf(";" + key + ";") >= 0) return true;

                        switch (validSettings.valType.toLowerCase()) {
                            case "number":
                                if (!((key >= 48 && key <= 57) || (key >= 96 && key <= 105) || key == 190 || key == 189 || key == 109 || key == 110))
                                    return false;
                                break;
                            case "int":
                                if (!((key >= 48 && key <= 57) || (key >= 96 && key <= 105)))
                                    return false;
                                break;
                            case "telphone":
                                if (!((key >= 48 && key <= 57) || (key >= 96 && key <= 105) || key == 189 || key == 109))
                                    return false;
                                break;
                            case "mobile":
                                if (!((key >= 48 && key <= 57) || (key >= 96 && key <= 105)))
                                    return false;
                                break;
                            case "date":
                                if (!((key >= 48 && key <= 57) || (key >= 96 && key <= 105) || (key >= 189 && key <= 191) || key == 32 || key == 109 || key == 110))
                                    return false;
                                break;
                        }


                    }).blur(function () {
                        $myself.attr("valid_ok", validate($myself));
                        ShowResult($myself);
                    });

                })
            });
        },
        clear: function () {
            this.find(valid_input_types).each(function () {
                var $this = $(this);//每一个input
                clearInputTips($this);
            });
        },
        refresh: function () {
            this.find(valid_input_types).each(function () {
                var $this = $(this);//每一个input
                clearInputTips($this);

                //200ms后刷新
                setTimeout(function () {
                    ShowResult($this);
                }, 200);
            });
        }
    };

    $.fn.validatorX = function () {
        //arguments[0]是传进来的第一个参数
        var method = arguments[0];

        if (methods[method]) {
            method = methods[method];
            arguments = Array.prototype.slice.call(arguments, 1);
        } else if (typeof(method) == 'object' || !method) {
            method = methods.init;
        } else {
            $.error('方法 ' + method + ' 并不存在于插件中！');
            return this;
        }

        //调用method方法，用this和arguments
        return method.apply(this, arguments);
    };


    /**
     * @return {boolean}
     */
    $.fn.Valid = function () {
        var can_submit = true;
        firstObj = null;
        this.find(valid_input_types).each(function () {
            //遍历每一个input
            var $this = $(this);
            if ($this.data("validSettings")) {

                if (!$this.attr("valid_ok") || $this.attr("valid_ok")=="false") {//验证不通过或者没有进行验证的
                    var result = validate($this);
                    if (!result) {//验证不通过
                        if (firstObj == null) {
                            firstObj = $this;
                        }
                        can_submit = false;
                    }
                    $this.attr("valid_ok", result);
                    ShowResult($this);
                }

            }
        });

        //获得焦点
        if (firstObj != null) {
            firstObj.focus();
            //滚动条移动到指定元素位置
            $("html,body").animate({scrollTop: firstObj.offsetTop}, 1000);
        }

        return can_submit;
    };

    //默认设置
    $.fn.validatorX.defaults = {};

})(jQuery);